<?php
/**
 * 유틸리티 - 캐쉬
 *
 * 캐쉬 유틸리티는 캐쉬설정, 캐쉬관리, 캐쉬쓰기를 관계 있게 설정할 수 있습니다.
 *
 * 캐쉬 유틸리티는 캐쉬설정>대상클래스 또는 그 이름>키 로 구성되어 있습니다.
 * 캐쉬 하나의 캐쉬 설정은 여러개의 '대상 클래스 또는 이름'으로 구성된 '캐쉬'를 관리합니다.
 * 캐쉬는 다수개의 키를 기준으로 캐쉬 데이터를 보유합니다.
 *
 * 예) 데이터베이스 파일 캐쉬(캐쉬유효관리:파일) - 캐쉬설정-데이터베이스파일/캐쉬 관리-파일/캐쉬쓰기-파일
 *
 * <code>
 * // 캐쉬 생성(아래는 예제는 기본값입니다.)
 * $aCacheConfig = array
 * (
 *     $aCacheConfig['ExpireTime'] = 86400,           // 캐쉬 유료 시간
 *     $aCacheConfig['Writer'] = 'File',    // 캐쉬 쓰기 처리자(현재 File을 지원합니다.)
 *     $aCacheConfig['WriterParser'] = 'Serial',    // 캐쉬 쓰기 파서(현재 Serial을 지원합니다.)
 *     $aCacheConfig['CacheManage'] = 'File',    // 캐쉬 관리 (File, Filememcache)
 *     $aCacheConfig['UseCache'] = false,    // 캐쉬 사용여부(사용:true|사용안함:false)
 *     $aCacheConfig['DefaultPath'] = FW_DIR_CACHE,    // 캐쉬 경로
 *     $aCacheConfig['DirectoryVariance'] = 0    // 캐쉬 분산(디렉토리 또는 키 분산)
 *      $aCacheConfig['MemcacheHost'] = 'localhost'     // 맴캐시 호스트 주소 (CacheManage 설정이 Filememcache 일 경우 유효함)
 *      $aCacheConfig['MemcachePort'] = 11211           // 맴캐시 포트 주소 (CacheManage 설정이 Filememcache 일 경우 유효함)
 * );
 *
 * $utilCache = new utilCache('DEBUG_CACHE', '$aCacheConfig');
 *
 * // 클래스 설정(한 캐쉬는 여러개의 클래스를 관리할 수 있습니다.)
 * $utilCache->setClass($testClass);
 *
 * // 캐쉬에 저장된 데이터 반환
 * $mData = $utilCache->getData('Key');
 *
 * // 캐쉬에 데이터 저장
 * $mResult = $utilCache->setData('Key', $mData);
 *
 * // 캐쉬 초기화(지정된 클래스의 캐쉬)
 * $utilCache->setClear();
 *
 * // 모든 캐쉬 초기화
 * $utilCache->setClearAll();
 *
 * //
 * or
 *
 * // 기존 설정을 참고하거나 기본 옵션으로 캐쉬 생성
 * $utilCache = new utilCache('DEBUG_CACHE');
 * </code>
 *
 * @package    util
 *
 * @version 1.0
 * @author    jylee3@simplexi.com
 */
class utilCache
{
    /**
     * 캐쉬 쓰기 객체
     * @var utilCacheWriterAbstract
     */
    protected $cacheWriter;

    /**
     * 캐쉬 관리 객체
     * @var utilCacheManageAbstract
     */
    protected $cacheManage;

    /**
     * 캐쉬 설정 객체
     * @var utilCacheConfig
     */
    protected $cacheConfig;

    /**
     * 캐쉬 클래스 이름
     * @var    String
     */
    protected $sClassName;

    /**
     * 캐쉬 키
     * @var String
     */
    protected $sKey;

    /**
     * 캐쉬 생성자
     *
     * <code>
     * // 캐쉬 생성(아래는 예제는 기본값입니다.)
     * $aCacheConfig = array
     * (
     *     $aCacheConfig['ExpireTime'] = 86400,           // 캐쉬 유료 시간
     *     $aCacheConfig['Writer'] = 'File',    // 캐쉬 쓰기 처리자(현재 File을 지원합니다.)
     *     $aCacheConfig['WriterParser'] = 'Serial',    // 캐쉬 쓰기 파서(현재 Serial을 지원합니다.)
     *     $aCacheConfig['CacheManage'] = 'File',    // 캐쉬 관리 (File, Filememcache)
     *     $aCacheConfig['UseCache'] = false,    // 캐쉬 사용여부(사용:true|사용안함:false)
     *     $aCacheConfig['DefaultPath'] = FW_DIR_CACHE,    // 캐쉬 경로
     *     $aCacheConfig['DirectoryVariance'] = 0    // 캐쉬 분산(디렉토리 또는 키 분산)
     *      $aCacheConfig['MemcacheHost'] = 'localhost'     // 맴캐시 호스트 주소 (CacheManage 설정이 Filememcache 일 경우 유효함)
     *      $aCacheConfig['MemcachePort'] = 11211           // 맴캐시 포트 주소 (CacheManage 설정이 Filememcache 일 경우 유효함)
     * );
     *
     * $utilCache = new utilCache('DEBUG_CACHE', '$aCacheConfig');
     *
     * $utilCache->setClass
     *
     * or
     *
     * // 기존 설정을 참고하거나 기본 옵션으로 캐쉬 생성
     * $utilCache = new utilCache('DEBUG_CACHE');
     * </code>
     *
     * @param    String    $sCacheName    캐쉬 이름
     * @param    Array    $aCacheConfig    캐쉬 설정
     */
    public function __construct($sCacheName, $aCacheConfig=array())
    {
        if (!is_string($sCacheName))    throw new exceptionRuntime('Cache Name Failed.');
        if (!is_array($aCacheConfig))    throw new exceptionRuntime('Cache Configration Failed.');

        $this->cacheConfig = utilCacheConfig::getInstance($sCacheName, $aCacheConfig);

        $this->cacheWriter = $this->getWriter($this->cacheConfig);
        $this->cacheManage = $this->getManage($this->cacheConfig);
    }

    /**
     * 캐쉬 클래스 설정
     *
     * 참고 : 캐쉬 클래스 설정에 의해 캐쉬 디렉토리가 변경됩니다.
     *
     * <code>
     * $utilCache = new utilCache('DEBUG_CACHE');
     * $utilCache->setClass($classObject);
     * </code>
     *
     * @param    Mixed    $mClass    클래스 이름  / 인스턴스
     *
     * @return    utilCache
     */
    public function setClass($mClass)
    {
        if (is_object($mClass)) {
            $this->sClassName = get_class($mClass);
        } else {
            $this->sClassName = $mClass;
        }

        return $this;
    }

    /**
     * 캐쉬 키 설정
     *
     * 참고 : 캐쉬 키에 의해 데이터를  참고합니다.(중복되지 않도록 해야합니다)
     *
     * <code>
     * $utilCache = new utilCache('DEBUG_CACHE');
     * $utilCache->setKey('KEY_IS');
     * </code>
     *
     * @param    Mixed    $mKey    키 인스턴스 / 키 배열 / 키 문자열
     *
     * @return    utilCache
     */
    public function setKey($mKey)
    {
        if (is_object($mKey)) {
            $this->sKey = md5(get_class($mKey));
        } else if (is_array($mKey)) {
            $this->sKey = md5(serialize($mKey));
        } else {
            $this->sKey = md5($mKey);
        }

        return $this;
    }

    /**
     * 캐쉬 존재 및 유효성 여부 반환
     *
     * <code>
     * $utilCache = new utilCache('DEBUG_CACHE');
     * $utilCache->setClass($classObject)->setKey('KEY_IS')->isCache();
     *
     * or
     *
     * $utilCache->isCache('KEY_IS', $classObject);
     *
     * or
     *
     * $utilCache->setClass($classObject)->isCache('KEY_IS');
     * </code>
     *
     * @param    Mixed    $mKey    키 인스턴스 / 키 배열 / 키 문자열
     * @param    Mixed    $mClass    클래스 이름  / 인스턴스
     *
     * @return    Boolean    캐쉬가 유효한 경우 true, 유효하지 않거나 없는 경우 false
     */
    public function isCache($mKey=null, $mClass=null)
    {
        if ($mKey !== null) {
            $this->setKey($mKey);
        }

        if ($mClass !== null) {
            $this->setClass($mClass);
        }

        if (empty($this->sClassName) || empty($this->sKey)) {
            throw new exceptionInvalid_argument('Class or Key Not Setting.');
        }

        return $this->cacheManage->isCacheExpired($this->sClassName, $this->sKey);
    }

    /**
     * 캐쉬 사용여부 설정 및 반환
     *
     * <code>
     * $utilCache = new utilCache('DEBUG_CACHE');
     * $utilCache->useCache(false);
     *
     * or
     *
     * $bUseCache = $utilCache->useCache();
     * </code>
     *
     * @param    Boolean    $bUseCache    캐쉬 사용여부, 사용시 ture, 사용하지 않을 경우 false, 값을 지정하지 않으면 설정되지 않음
     *
     * @return Boolean    캐쉬를 사용할 경우 true, 캐쉬를 사용하지 않을 경우 false
     */
    public function useCache($bUseCache=null)
    {
        if (is_bool($bUseCache)) {
            $this->cacheConfig->bUseCache = $bUseCache;
        }

        return $this->cacheConfig->bUseCache;
    }

    /**
     * 캐쉬 데이터 가져오기
     *
     * <code>
     * $utilCache = new utilCache();
     * $utilCache->setClass($classObject)->setKey('KEY_IS')->getData();
     *
     * or
     *
     * $utilCache->getData('KEY_IS', $classObject);
     *
     * or
     *
     * $utilCache->setClass($classObject)->getData('KEY_IS');
     * </code>
     *
     * @param    Mixed    $mKey    키 인스턴스 / 키 배열 / 키 문자열
     * @param    Mixed    $mClass    클래스 이름  / 인스턴스
     *
     * @return    Mixed    캐쉬 데이터
     *
     * @throws exceptionInvalid_argument
     */
    public function getData($mKey=null, $mClass=null)
    {
        if ($mKey !== null) {
            $this->setKey($mKey);
        }

        if ($mClass !== null) {
            $this->setClass($mClass);
        }

        if (empty($this->sClassName) || empty($this->sKey)) {
            throw new exceptionInvalid_argument('Class or Key Not Setting.');
        }

        if ($this->isCache()) {
            return $this->cacheWriter->getData($this->sClassName, $this->sKey);
        } else {
            return false;
        }
    }

    /**
     * 캐쉬 데이터 저장
     *
     * <code>
     * $utilCache = new utilCache('DEBUG_CACHE');
     * $utilCache->setClass($classObject)->setKey('KEY_IS')->setData('SaveData');
     *
     * or
     *
     * $utilCache->setData('SaveData', 'KEY_IS', $classObject);
     *
     * or
     *
     * $utilCache->setClass($classObject)->setData('SaveData', 'KEY_IS');
     * </code>
     *
     * @param    Mixed    $mData    캐쉬 데이터
     * @param    Mixed    $mKey    키 인스턴스 / 키 배열 / 키 문자열
     * @param    Mixed    $mClass    클래스 이름  / 인스턴스
     *
     * @return    Mixed    캐쉬 저장 성공시 캐쉬 설정 경로, 실패시 false
     */
    public function setData($mData, $mKey=null, $mClass=null)
    {
        if ($mKey !== null) {
            $this->setKey($mKey);
        }

        if ($mClass !== null) {
            $this->setClass($mClass);
        }

        if (empty($this->sClassName) || empty($this->sKey)) {
            throw new exceptionInvalid_argument('Class or Key Not Setting.');
        }

        $mResult1 = $this->cacheManage->setCacheManage($this->sClassName, $this->sKey);
        $mResult2 = $this->cacheWriter->setData($this->sClassName, $this->sKey, $mData);

        return ($mResult1!==false && $mResult2!==false)? $mResult2 : false;
    }

    /**
     * 캐쉬 초기화(클래스 캐쉬 전체)
     *
     * <code>
     * $utilCache = new utilCache('DEBUG_CACHE');
     * $utilCache->setClass($classObject)->setClear();
     *
     * or
     *
     * $utilCache->setClear($classObject);
     * </code>
     *
     * @param    Mixed    $mObject    클래스 이름  / 인스턴스
     *
     * @return    Boolean    성공시 true, 실패시 false
     */
    public function setClear($mObject=null)
    {
        if ($mObject !== null) {
            $this->setClass($mObject);
        }

        $this->sKey = null;

        if (empty($this->sClassName)) {
            throw new exceptionInvalid_argument('Class Not Setting.');
        }

        $bManagerClear = $this->cacheManage->setClear($this->sClassName);

        return $bManagerClear;

    }

    /**
     * 캐쉬 설정 반환
     *
     * @return utilCacheConfig
     */
    public function getCacheConfig()
    {
        return $this->cacheConfig;
    }

    /**
     * 캐쉬 전체 초기화
     *
     * <code>
     * $utilCache = new utilCache('DEBUG_CACHE');
     * $utilCache->setClearAll();
     * </code>
     *
     * @return    Boolean    성공시 true, 실패시 false
     */
    public function setClearAll()
    {
        //return ($this->cacheManage->setClearAll() && $this->cacheWriter->setClearAll());
        return $this->cacheManage->setClearAll();
    }

    protected function getWriter(utilCacheConfig $mCacheConfig)
    {
        $sClassName = 'utilCacheWriter'.$mCacheConfig->sWriter;

        return new $sClassName($mCacheConfig);
    }

    protected function getManage(utilCacheConfig $mCacheConfig)
    {
        $sClassName = 'utilCacheManage'.$mCacheConfig->sManage;

        return new $sClassName($mCacheConfig);
    }
}
